package com.zmn.oms.zmn.business.impl.callcenterstat;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.zmn.common.constant.GlobalConsts;
import com.zmn.oms.business.impl.base.AbstractListEsQueryServiceImpl;
import com.zmn.oms.business.interfaces.es.OrderWorkEsBService;
import com.zmn.oms.common.constant.OrderConsts;
import com.zmn.oms.common.constant.OrderStatusConsts;
import com.zmn.oms.model.bo.work.EsQueryBuilder;
import com.zmn.oms.model.entity.callcenterstat.EsOrderStat;
import com.zmn.oms.model.entity.work.OrderWorkQuery;
import com.zmn.oms.zmn.business.interfaces.callcenterstat.CallCenterEsOrderStatBService;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.bucket.terms.ParsedLongTerms;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;

/**
 * 描述: call center stat es order 实现
 *
 * @author wangjie
 * @date 15:08 2019/3/14
 **/
@Service
public class CallCenterEsOrderStatBServiceImpl extends AbstractListEsQueryServiceImpl implements CallCenterEsOrderStatBService {

    private static final Logger logger = LoggerFactory.getLogger(CallCenterEsOrderStatBServiceImpl.class);

    @Resource
    OrderWorkEsBService orderWorkEsBService;

    /**
     * 描述: es page_index
     *
     * @author wangjie
     * @date 10:55 2019/7/1
     **/
    private static final Integer ES_PAGE_INDEX = 0;
    /**
     * 描述: es_page_size
     *
     * @author wangjie
     * @date 10:56 2019/7/1
     **/
    private static final Integer ES_PAGE_SIZE = 100;

    /**
     * 描述: 根据时间段,操作人分组统计es order 数据
     *
     * @param startDate 开始时间
     * @param endDate   结束时间
     * @return java.util.List<com.zmn.oms.model.entity.callcenterstat.EsOrderStat>
     * @author wangjie
     * @date 15:04 2019/3/14
     **/
    @Override
    @SuppressWarnings("Duplicates")
    public List<EsOrderStat> statEsOrderGroupByOperatorId(String startDate, String endDate, Integer channelId) {

        HashMap<Long, EsOrderStat> newOrderCount = Maps.newHashMap();
        try {
            // 新单 并获得一个操作人id为key 的map
            newOrderCount = findNewOrderCountMap(startDate, endDate, channelId);
            //返修量
            this.findRepairOrderCountMap(startDate, endDate, newOrderCount, channelId);
            //回访量
            this.findReplyOrderCountMap(startDate, endDate, newOrderCount, channelId);
            //上门
            this.findVisitOrderCountMap(startDate, endDate, newOrderCount, channelId);
            //成功单量,以派单时间计算
            this.findSuccessfulOrderCountMap(startDate, endDate, newOrderCount, channelId);
        } catch (Exception e) {
            logger.error("根据时间段,操作人分组统计es order 数据 查询失败,Exception{},msg{}", e, e.getMessage());
        }
        return new ArrayList<>(newOrderCount.values());
    }

    /**
     * 描述: 生成共用查询条件
     *
     * @param startDate     开始时间
     * @param endDate       结束时间
     * @param channelId     渠道id
     * @param workType      工单类型
     * @param operatorGroup 操作人分组标识
     * @param termsName     分组名称
     * @return org.springframework.data.elasticsearch.core.query.NativeSearchQuery
     * @author wangjie
     * @date 10:29 2019/7/1
     **/
    private NativeSearchQuery builderSearchQuery(String startDate, String endDate, Integer channelId, Integer workType,
                                                 String termsName, String operatorGroup) throws Exception {

        OrderWorkQuery query = new OrderWorkQuery();
        query.setPageSize(ES_PAGE_SIZE);
        query.setReceiveTime(startDate + "," + endDate);
        query.setWorkType(Lists.newArrayList(workType));
        query.setDuplicate(GlobalConsts.NO);
        if (Objects.nonNull(channelId)) {
            query.setChannelIdList(Lists.newArrayList(channelId));
        }
        return this.builderSearchQuery(query, termsName, operatorGroup);
    }

    /**
     * 描述: 构建es 查询
     *
     * @param query         查询条件
     * @param termsName     分组名称
     * @param operatorGroup 操作人分组标识
     * @return org.springframework.data.elasticsearch.core.query.NativeSearchQuery
     * @author wangjie
     * @date 10:47 2019/7/1
     **/
    private NativeSearchQuery builderSearchQuery(OrderWorkQuery query, String termsName, String operatorGroup) throws Exception {
        BoolQueryBuilder queryBuilder = EsQueryBuilder.getQuery(query);
        NativeSearchQuery searchQuery = new NativeSearchQuery(queryBuilder);
        searchQuery.setPageable(PageRequest.of(ES_PAGE_INDEX, ES_PAGE_SIZE));
        TermsAggregationBuilder termsAggregationBuilder = AggregationBuilders.terms(termsName).field(operatorGroup).size(10000);
        searchQuery.addAggregation(termsAggregationBuilder);
        return searchQuery;
    }


    /**
     * 描述: 查询新单
     *
     * @param startDate 开始时间
     * @param endDate   结束时间
     * @param channelId 渠道id
     * @return java.util.HashMap<java.lang.Long, com.zmn.oms.model.entity.callcenterstat.EsOrderStat>
     * @author wangjie
     * @date 17:36 2019/6/28
     **/
    private HashMap<Long, EsOrderStat> findNewOrderCountMap(String startDate, String endDate, Integer channelId) throws Exception {

        NativeSearchQuery nativeSearchQuery = this.builderSearchQuery(startDate, endDate, channelId,
                OrderConsts.ORDER_TYPE_NEW, "operator_id", "receiverId");

        Aggregations aggregations = orderWorkEsBService.getAggregationsByQuery(nativeSearchQuery);
        ParsedLongTerms operator = aggregations.get("operator_id");
        List<? extends Terms.Bucket> buckets = operator.getBuckets();
        HashMap<Long, EsOrderStat> esOrderHashMap = Maps.newHashMapWithExpectedSize(buckets.size());
        buckets.forEach(e -> {
            String key = e.getKeyAsString();
            long operatorId = new Long(key);
            long docCount = Optional.of(e.getDocCount()).orElse(0L);
            EsOrderStat esOrderStat = new EsOrderStat();
            esOrderStat.setOperatorId(operatorId);
            esOrderStat.setOrderCount((int) docCount);
            esOrderHashMap.put(operatorId, esOrderStat);
        });
        return esOrderHashMap;
    }

    /**
     * 描述: 该话务录入的返修量 录入时间
     *
     * @param startDate 开始时间
     * @param endDate   结束时间
     * @param map       根据录入时间条件查询的元数据
     * @author wangjie
     * @date 10:09 2019/3/16
     **/
    private void findRepairOrderCountMap(String startDate, String endDate, HashMap<Long, EsOrderStat> map, Integer channelId) throws Exception {

        NativeSearchQuery nativeSearchQuery = this.builderSearchQuery(startDate, endDate, channelId,
                OrderConsts.ORDER_TYPE_REWORK, "operator_id", "receiverId");

        Aggregations aggregations = orderWorkEsBService.getAggregationsByQuery(nativeSearchQuery);
        ParsedLongTerms operator = aggregations.get("operator_id");
        List<? extends Terms.Bucket> buckets = operator.getBuckets();
        buckets.forEach(bucket -> {
            String key = bucket.getKeyAsString();
            long operatorId = new Long(key);
            long docCount = Optional.of(bucket.getDocCount()).orElse(0L);
            if (Objects.isNull(map.get(operatorId))) {
                EsOrderStat esOrderStat = new EsOrderStat();
                esOrderStat.setOperatorId(operatorId);
                esOrderStat.setRepairCount((int) docCount);
                map.put(operatorId, esOrderStat);
            } else {
                map.get(operatorId).setRepairCount((int) docCount);
            }
        });
    }

    /**
     * 描述: 按回访时间计算(条件) 获得回访单量 如果元map 里没有这个数据 则添加
     *
     * @param startDate 开始时间
     * @param endDate   结束时间
     * @param map       根据录入时间条件查询的元数据
     * @author wangjie
     * @date 10:27 2019/3/16
     **/
    @SuppressWarnings("Duplicates")
    private void findReplyOrderCountMap(String startDate, String endDate, HashMap<Long, EsOrderStat> map, Integer channelId) throws Exception {

        OrderWorkQuery query = new OrderWorkQuery();
        query.setPageSize(ES_PAGE_SIZE);
        query.setReplyVisitTime(startDate + "," + endDate);
        query.setDuplicate(GlobalConsts.NO);
        query.setReplyVisited(GlobalConsts.YES);
        if (Objects.nonNull(channelId)) {
            query.setChannelIdList(Lists.newArrayList(channelId));
        }
        NativeSearchQuery nativeSearchQuery = this.builderSearchQuery(query, "operator_id", "receiverId");
        Aggregations aggregations = orderWorkEsBService.getAggregationsByQuery(nativeSearchQuery);
        ParsedLongTerms operator = aggregations.get("operator_id");
        List<? extends Terms.Bucket> buckets = operator.getBuckets();
        buckets.forEach(bucket -> {
            String key = bucket.getKeyAsString();
            long operatorId = new Long(key);
            long docCount = Optional.of(bucket.getDocCount()).orElse(0L);
            if (Objects.isNull(map.get(new Long(key)))) {
                EsOrderStat esOrderStat = new EsOrderStat();
                esOrderStat.setOperatorId(operatorId);
                esOrderStat.setCallBackCount((int) docCount);
                map.put(operatorId, esOrderStat);
            } else {
                map.get(operatorId).setCallBackCount((int) docCount);
            }
        });
    }

    /**
     * 描述: 根据上门时间查询 上门订单
     *
     * @param startDate 开始时间
     * @param endDate   结束时间
     * @param channelId 渠道id
     * @param map       根据录入时间条件查询的元数据
     * @author wangjie
     * @date 13:50 2019/3/16
     **/
    @SuppressWarnings("Duplicates")
    private void findVisitOrderCountMap(String startDate, String endDate, HashMap<Long, EsOrderStat> map, Integer channelId) throws Exception {

        OrderWorkQuery query = new OrderWorkQuery();
        query.setPageSize(ES_PAGE_SIZE);
        query.setVisitTime(startDate + "," + endDate);
        query.setDuplicate(GlobalConsts.NO);
        if (Objects.nonNull(channelId)) {
            query.setChannelIdList(Lists.newArrayList(channelId));
        }
        query.setOperatorType(GlobalConsts.NO);
        NativeSearchQuery nativeSearchQuery = this.builderSearchQuery(query, "operator_id", "receiverId");
        Aggregations aggregations = orderWorkEsBService.getAggregationsByQuery(nativeSearchQuery);
        ParsedLongTerms operator = aggregations.get("operator_id");
        List<? extends Terms.Bucket> buckets = operator.getBuckets();
        buckets.forEach(bucket -> {
            String key = bucket.getKeyAsString();
            long operatorId = new Long(key);
            long docCount = Optional.of(bucket.getDocCount()).orElse(0L);
            if (Objects.isNull(map.get(operatorId))) {
                EsOrderStat esOrderStat = new EsOrderStat();
                esOrderStat.setOperatorId(operatorId);
                esOrderStat.setVisitCount((int) docCount);
                map.put(operatorId, esOrderStat);
            } else {
                map.get(operatorId).setVisitCount((int) docCount);
            }
        });
    }

    /**
     * 描述: 获得操作员成功的单量,派单时间内，完成的新单，结果是：成功
     *
     * @param startDate 开始时间
     * @param endDate   结束时间
     * @param channelId 渠道id
     * @param map       根据录入时间条件查询的元数据
     * @author wangjie
     * @date 15:02 2019/4/1
     **/
    private void findSuccessfulOrderCountMap(String startDate, String endDate, HashMap<Long, EsOrderStat> map, Integer channelId) throws Exception {

        OrderWorkQuery query = new OrderWorkQuery();
        query.setPageSize(ES_PAGE_SIZE);
        query.setDistributeTime(startDate + "," + endDate);
        query.setDuplicate(GlobalConsts.NO);
        if (Objects.nonNull(channelId)) {
            query.setChannelIdList(Lists.newArrayList(channelId));
        }
        query.setOperatorType(GlobalConsts.NO);
        query.setResultStatusList(Lists.newArrayList(OrderStatusConsts.WORK_RESULT_SUCCESS));

        NativeSearchQuery nativeSearchQuery = this.builderSearchQuery(query, "operator_id", "receiverId");
        Aggregations aggregations = orderWorkEsBService.getAggregationsByQuery(nativeSearchQuery);
        ParsedLongTerms operator = aggregations.get("operator_id");
        List<? extends Terms.Bucket> buckets = operator.getBuckets();
        buckets.forEach(bucket -> {
            String key = bucket.getKeyAsString();
            long operatorId = new Long(key);
            long docCount = Optional.of(bucket.getDocCount()).orElse(0L);
            if (Objects.isNull(map.get(operatorId))) {
                EsOrderStat esOrderStat = new EsOrderStat();
                esOrderStat.setOperatorId(operatorId);
                esOrderStat.setSuccessfulOrderCount((int) docCount);
                map.put(new Long(key), esOrderStat);
            }
            map.get(operatorId).setSuccessfulOrderCount((int) docCount);
        });
    }
}